/* CoralCube | Massively Multiplayer Online Role-Playing Game(MMORPG) Emulator.
|* 
|* Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
|*               2008-2010 TrinityCore <http://www.trinitycore.org/>
|*               2008-2010 CoralCube <http://www.CoralCube.com/>
|*
|* This program is free software. You can redistribute it and/or modify it under the terms of 
|* the GNU General Public License as published by the Free Software Foundation, either 
|* version 2 of the License.
|*
|* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, 
|* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
|* See the GNU General Public License for more details.
|*
|* You should have received a copy of the GNU General Public License along with this program. 
|* If not, see <http://www.gnu.org/licenses/>.
|*/

#ifndef CORE_TARGETEDMOVEMENTGENERATOR_H
#define CORE_TARGETEDMOVEMENTGENERATOR_H

#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
#include "FollowerReference.h"

class TargetedMovementGeneratorBase
{
public:
    TargetedMovementGeneratorBase(Unit &target) { i_target.link(&target, this); }
    void stopFollowing() { }
protected:
    FollowerReference i_target;
};

template<class T>
class TargetedMovementGenerator
: public MovementGeneratorMedium< T, TargetedMovementGenerator<T> >, public TargetedMovementGeneratorBase
{
public:
    TargetedMovementGenerator(Unit &target, float offset = 0, float angle = 0);
    ~TargetedMovementGenerator() { }

    void Initialize(T &);
    void Finalize(T &);
    void Reset(T &);
    bool Update(T &, const uint32 &);
    MovementGeneratorType GetMovementGeneratorType() { return TARGETED_MOTION_TYPE; }

    void MovementInform(T &);

    Unit* GetTarget() const;

    bool GetDestination(float &x, float &y, float &z) const
    {
        if (i_destinationHolder.HasArrived() || !i_destinationHolder.HasDestination()) return false;
        i_destinationHolder.GetDestination(x,y,z);
        return true;
    }

    void unitSpeedChanged() { i_recalculateTravel=true; }
private:

    bool _setTargetLocation(T &);

    float i_offset;
    float i_angle;
    DestinationHolder< Traveller<T> > i_destinationHolder;
    bool i_recalculateTravel;
        float i_targetX, i_targetY, i_targetZ;
};
#endif
